import type { Feature, FeatureCollection } from 'geojson'
import type { Map } from 'mapbox-gl'
import type { Layer } from './types'
import type mapboxgl from 'mapbox-gl'

export default abstract class BaseLayer implements Layer {
  public readonly id: string
  public readonly name: string
  protected map: mapboxgl.Map | undefined // map实例
  protected isVisible: boolean // 图层是否可见
  private featureData: FeatureCollection
  private before: string | null

  constructor(
    id: string,
    name: string,
    visible: boolean = true,
    features_: Feature[] | undefined = undefined,
    before: string | undefined | null = undefined
  ) {
    this.id = id
    this.name = name
    const features = features_ || []
    this.featureData = { type: 'FeatureCollection', features }
    this.isVisible = visible
    this.before = before === undefined ? 'overlay#fill' : before
  }

  // 返回图层可见性
  public get visible(): boolean {
    return this.isVisible
  }

  // 设置图层的可见性
  public set visible(ok: boolean) {
    if (this.isVisible === ok) {
      return
    }
    this.isVisible = ok
    if (this.map) {
      this.map.setLayoutProperty(this.id, 'visibility', this.isVisible ? 'visible' : 'none')
    }
  }

  public attach(map: Map): void {
    if (this.map) {
      return
    }
    this.map = map
    const layer = this.makeMapBoxGLLayer() as mapboxgl.Layer
    layer.id = this.id
    layer.source = { type: 'geojson', data: this.featureData }
    const visibility = this.isVisible ? 'visible' : 'none'
    if (!layer.layout) {
      layer.layout = { visibility }
    } else {
      layer.layout.visibility = visibility
    }
    this.map.addLayer(layer as mapboxgl.AnyLayer, this.before || undefined)
  }
  // 重绘函数
  protected repaint(lst: Feature[] | undefined) {
    if (lst) {
      this.featureData.features = lst
    }
    if (!this.map) {
      return
    }

    ;(this.map.getSource(this.id) as mapboxgl.GeoJSONSource).setData(this.featureData)
  }

  // 生成mapboxgl图层GEOJSON数据
  protected abstract makeMapBoxGLLayer(): Omit<mapboxgl.Layer, 'source'>
}
